package com.cancer.common.util;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ReflectUtil {
	public static Field[] getFields(Class<?> clz) {

		return clz.getDeclaredFields();
	}

	public static Method[] getMethods(Class<?> clz) {

		return clz.getDeclaredMethods();
	}
	
	public static List<Field> getAllField(Class<?> clz) {
		List<Field> list = new ArrayList<Field>();
		
		//获取当前类的所有属性
		Field[] fs = clz.getDeclaredFields();
		list.addAll(Arrays.asList(fs));
		
		//获取父类的所有属性
		Class<?> curr = clz.getSuperclass();
		while (!curr.equals(Object.class)) {
			Field[] sfs = curr.getDeclaredFields();
			list.addAll(Arrays.asList(sfs));
			curr = curr.getSuperclass();
		}
		
		return list;
	}

	/**
	 * 根据包名获取包下所有的类名
	 * 
	 * @author 刘俊 2015年5月7日
	 * @param basePackage
	 * @return
	 */
	public static List<String> getClassNameByPackage(String basePackage) {
		List<String> clzNames = new ArrayList<>();

		if (basePackage != null && !"".equals(basePackage.trim())) {
			String realPath = getPackageRealPath(basePackage);
			recurseClass(clzNames, basePackage, new File(realPath));
		}
		
		return clzNames;
	}
	
	public static List<Class<?>> getClasses(String packageName) {
		// 第一个class类的集合
		List<Class<?>> classes = new ArrayList<Class<?>>();
		// 是否循环迭代
		boolean recursive = true;
		// 获取包的名字 并进行替换
		String packageDirName = packageName.replace('.', '/');
		// 定义一个枚举的集合 并进行循环来处理这个目录下的things
		Enumeration<URL> dirs;
		try {
			dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			// 循环迭代下去
			while (dirs.hasMoreElements()) {
				// 获取下一个元素
				URL url = dirs.nextElement();
				// 得到协议的名称
				String protocol = url.getProtocol();
				// 如果是以文件的形式保存在服务器上
				if ("file".equals(protocol)) {
					// 获取包的物理路径
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
					// 以文件的方式扫描整个包下的文件 并添加到集合中
					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				} else if ("jar".equals(protocol)) {
					// 如果是jar包文件
					// 定义一个JarFile
					JarFile jar;
					try {
						// 获取jar
						jar = ((JarURLConnection) url.openConnection()).getJarFile();
						// 从此jar包 得到一个枚举类
						Enumeration<JarEntry> entries = jar.entries();
						// 同样的进行循环迭代
						while (entries.hasMoreElements()) {
							// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
							JarEntry entry = entries.nextElement();
							String name = entry.getName();
							// 如果是以/开头的
							if (name.charAt(0) == '/') {
								// 获取后面的字符串
								name = name.substring(1);
							}
							// 如果前半部分和定义的包名相同
							if (name.startsWith(packageDirName)) {
								int idx = name.lastIndexOf('/');
								// 如果以"/"结尾 是一个包
								if (idx != -1) {
									// 获取包名 把"/"替换成"."
									packageName = name.substring(0, idx).replace('/', '.');
								}
								// 如果可以迭代下去 并且是一个包
								if ((idx != -1) || recursive) {
									// 如果是一个.class文件 而且不是目录
									if (name.endsWith(".class") && !entry.isDirectory()) {
										// 去掉后面的".class" 获取真正的类名
										String className = name.substring(packageName.length() + 1, name.length() - 6);
										try {
											// 添加到classes
											classes.add(Class.forName(packageName + '.' + className));
										} catch (ClassNotFoundException e) {
											e.printStackTrace();
										}
									}
								}
							}
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return classes;
	}

	/**
	 * 以文件的形式来获取包下的所有Class
	 * 
	 * @param packageName
	 * @param packagePath
	 * @param recursive
	 * @param classes
	 */
	public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,
			List<Class<?>> classes) {
		// 获取此包的目录 建立一个File
		File dir = new File(packagePath);
		// 如果不存在或者 也不是目录就直接返回
		if (!dir.exists() || !dir.isDirectory()) {
			return;
		}
		// 如果存在 就获取包下的所有文件 包括目录
		File[] dirfiles = dir.listFiles(new FileFilter() {
			// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
			public boolean accept(File file) {
				return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
			}
		});
		// 循环所有文件
		for (File file : dirfiles) {
			// 如果是目录 则继续扫描
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
			} else {
				// 如果是java类文件 去掉后面的.class 只留下类名
				String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					// 添加到集合中去
					classes.add(Class.forName(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
	}


	/**
	 * 获取包所在的绝对路径
	 * 
	 * @author 刘俊 2016年5月21日
	 * @param basePackage
	 * @return
	 */
	public static String getPackageRealPath(String basePackage) {
		String realPath = ReflectUtil.class.getClassLoader().getResource(basePackage.replace(".", "/")).getPath();
		
		return realPath;
	}
	
	/**
	 * 递归获取所有类
	 * 
	 * @author 刘俊 2016年5月21日
	 * @param clzNames
	 * @param basePackage
	 * @param root
	 */
	private static void recurseClass(List<String> clzNames, String basePackage, File root) {
		if (!root.exists()) {
			return;
		}
		if (root.isDirectory()) {
			String[] list = root.list();
			for (String fname : list) {
				recurseClass(clzNames, basePackage + "." + fname, new File(root + File.separator + fname));
			}
		} else {
			clzNames.add(basePackage.replace(".class", ""));
		}
	}
	
	/**
	 * 调用set方法设置属性值
	 * 
	 * @author 刘俊 2015年5月11日
	 * @param obj		调用对象
	 * @param propName	属性
	 * @param value		值
	 */
	public static void setProperty(Object obj, String propName, Object value) {
		try {
			PropertyDescriptor propDesc = new PropertyDescriptor(propName, obj.getClass());
			Method set = propDesc.getWriteMethod();

			set.invoke(obj, convert(getPropType(obj.getClass(), propName), value));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 调用get方法获取属性值
	 * 
	 * @author 刘俊 2015年5月11日
	 * @param obj		调用对象
	 * @param propName	属性
	 * @return			值
	 */
	public static Object getProperty(Object obj, String propName) {
		Object value;
		try {
			PropertyDescriptor proDescriptor = new PropertyDescriptor(propName, obj.getClass());
			Method get = proDescriptor.getReadMethod();
			value = get.invoke(obj);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		return value;
	}

	/**
	 * 获取属性的数据类型
	 * 
	 * @author 刘俊 2015年5月11日
	 * @param clz		类
	 * @param propName	类的属性
	 * @return			属性的数据类型
	 */
	public static Class<?> getPropType(Class<?> clz, String propName) {
		try {
			Field f = null;
			try { f = clz.getDeclaredField(propName); } catch (NoSuchFieldException e) {}
			
			while (!clz.equals(Object.class) && f == null) {
				clz = clz.getSuperclass();
				try { f = clz.getDeclaredField(propName); } catch (NoSuchFieldException e) {}
			}
			return f.getType();
		} catch (Exception e) {
			System.err.println("获取" + propName + "类型失败. 原因: " + e.getMessage());
		}

		return Object.class;
	}

	/**
	 * 基础数据类型转换 
	 * 
	 * @author 刘俊 2015年5月11日
	 * @param propType	值类型
	 * @param value		值
	 * @return
	 */
	public static Object convert(Class<?> propType, Object value) {
		if (value == null) {
			if (propType.isPrimitive()) {
				if (propType.equals(Boolean.TYPE)) {
					return false;
				} else {
					return 0;
				}
			} else {
				return null;
			}
		} else if (propType.equals(String.class)) {
			return value;
		} else if (propType.equals(Integer.TYPE) || propType.equals(Integer.class)) {
			return Integer.valueOf(value.toString());
		} else if (propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) {
			return Boolean.valueOf(value.toString());
		} else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) {
			return Long.valueOf(value.toString());
		} else if (propType.equals(Double.TYPE) || propType.equals(Double.class)) {
			return Double.valueOf(value.toString());
		} else if (propType.equals(Float.TYPE) || propType.equals(Float.class)) {
			return Float.valueOf(value.toString());
		} else if (propType.equals(Short.TYPE) || propType.equals(Short.class)) {
			return Short.valueOf(value.toString());
		} else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) {
			return Byte.valueOf(value.toString());
		}  else {
			return value;
		} 
	}
	
	/**
	 * 获取线程正在执行的方法
	 * 
	 * @author 刘俊 2016年1月22日
	 * @param th
	 * @return
	 */
	public static String getCurrendMethod(Thread th) {
		StackTraceElement stack = Thread.currentThread().getStackTrace()[2];

		return stack.getMethodName();
	}

	/**
	 * 将value转换为指定类型
	 *
	 * @autohr 刘俊  2016年2月22日
	 * @param type		目标类型
	 * @param value		值
	 * @return
	 */
	public static Object parsePrimitiveType(Class<?> type, String value) {
		if (StringUtil.isEmpty(value)) {
			return null;
		}
		
		if (Integer.TYPE.equals(type) || Integer.class.equals(type)) {
			return Integer.parseInt(value);
			
		} else if (Boolean.TYPE.equals(type) || Boolean.class.equals(type)) {
			return Boolean.parseBoolean(value);
			
		} else if (Long.TYPE.equals(type) || Long.class.equals(type)) {
			return Long.parseLong(value);
			
		} else if (Double.TYPE.equals(type) || Double.class.equals(type)) {
			return Double.parseDouble(value);
			
		} else if (Float.TYPE.equals(type) || Float.class.equals(type)) {
			return Float.parseFloat(value);
			
		} else if (Character.TYPE.equals(type) || Character.class.equals(type)) {
			return value.charAt(0);
			
		} else if (Byte.TYPE.equals(type) || Byte.class.equals(type)) {
			return Byte.parseByte(value);
			
		} else if (Short.TYPE.equals(type) || Short.class.equals(type)) {
			return Short.parseShort(value);
		}
		
		return null;
	}
	
	/**
	 * 获取基本类型的默认值
	 *
	 * @autohr 刘俊  2016年2月22日
	 * @param type
	 * @return
	 */
	public static Object getPrimitiveTypeDefaultValue(Class<?> type) {
		if (Integer.TYPE.equals(type)) {
			return 0;
			
		} else if (Boolean.TYPE.equals(type)) {
			return false;
			
		} else if (Long.TYPE.equals(type)) {
			return 0l;
			
		} else if (Double.TYPE.equals(type)) {
			return 0.0d;
			
		} else if (Float.TYPE.equals(type)) {
			return 0.0f;
			
		} else if (Character.TYPE.equals(type)) {
			return (char) 0;
			
		} else if (Byte.TYPE.equals(type)) {
			return (byte) 0;
			
		} else if (Short.TYPE.equals(type)) {
			return (short) 0;
		}
		
		return null;
	}
	
	/**
	 * 判断b是否是a的子类
	 *
	 * @autohr 刘俊  2016年2月26日
	 * @param a
	 * @param b
	 * @return
	 */
	public static boolean isParent(Class<?> a, Class<?> b) {
		while (b != null) {
			if (a.equals(b)) {
				return true;
			} else {
				b = b.getSuperclass();
			}
		}
		
		return false;
	}
	
	/**
	 * 判断类是否被注有某个注解
	 * 
	 * @author 刘俊 2016年5月21日
	 * @param clz
	 * @param anno
	 * @return
	 */
	public static boolean hasAnnotation(Class<?> clz, Class<? extends Annotation> anno) {
		return clz.isAnnotationPresent(anno);
	}

}
